package com.atguigu.gulimall.search.thread;

import java.util.concurrent.*;

public class ThreadTest {

    //线程池
     public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    /**
     * 1.继承Thread
     *     Thread01 thread01 = new Thread01();
     *     thread01.start();
     *
     *  2.实现Runnable接口
     *     Runnable01 runnable = new Runnable01();
     *     new Thread(runnable).start();
     *
     *  3.实现Callable接口+FutureTask（可以拿到返回结果，可以处理异常）
     *      FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
     *      new Thread(futureTask).start();
     *      阻塞等待整个线程执行完成，获取返回结果
     *      Integer integer = futureTask.get();
     *
     *  4.线程池
     *      给线程池直接提交任务。
     *
     *
     *  区别：
     *      1 2 不能得到返回值。3可以获取返回值
     *      1 2 3都不能控制资源
     *      4可以控制资源，性能稳定
     *
     *   以后业务代码中以上三种都不用，将所有多线程任务交给线程池
     *   当前系统中只有一两个线程池，每个异步任务都要提交给线程池，让线程池去执行。
     */

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //=====================================基础线程=======================================================================
//        Thread01 thread = new Thread01();
//        thread.start();
//
//        Runnable01 runnable = new Runnable01();
//        new Thread(runnable).start();
//
//        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
//        new Thread(futureTask).start();
//
//        executorService.execute(new Runnable01());
//=================================================线程池===========================================================
        /**
         * 线程池都7大参数
         * @param corePoolSize 核心线程数，一直存在的（除非allowCoreThreadTimeOut）;;
         *
         * @param maximumPoolSize 最大线程数；控制资源
         *      *
         * @param keepAliveTime 存活时间，大于核心线程数的线程超时没有任务会释放

         * @param unit 时间单位TimeUtils
         * @param workQueue 阻塞队列。如果任务有很多，就会将目前多的任务放在队列中。只要线程有空闲，就会来队列中取任务

         *@param threadFactory 线程创建工程，使用默认
         * @param RejectedExecutionHandle handler 如果队列中满了，线程也达到最大线程数了，按照指定的拒绝策略拒绝执行任务
         *      *        because the thread bounds and queue capacities are reached
         *      * @throws IllegalArgumentException if one of the following holds:<br>
         *      *         {@code corePoolSize < 0}<br>
         *      *         {@code keepAliveTime < 0}<br>
         *      *         {@code maximumPoolSize <= 0}<br>
         *      *         {@code maximumPoolSize < corePoolSize}
         *      * @throws NullPointerException if {@code workQueue}
         *      *         or {@code threadFactory} or {@code handler} is null
         *
         * 工作顺序：
         *      1。线程池创建，最备好core核心线程数量，准备接受任务
         *      2。core任务满了。就将任务放进队列中，等空闲等core来取
         *      3。阻塞队列满了，就会开新等线程来执行，最大开到max指定的数量
         *      4。max满了，就会使用RejectedExecutionHandle拒绝策略来拒绝任务
         *      5。max都执行完成了，有空闲都线程，在指定的keepAliveTime时间后释放线程
         *
         *        new LinkedBlockingDeque<>():默认Interger的最大值，会造成内存不够
         */
//        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
//                100,
//                10,
//                TimeUnit.SECONDS,
//                new LinkedBlockingDeque<>(100000),
//                Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.AbortPolicy());

        //一个线程池：core 7 ；max 20; queue 50 ,现在来100个任务怎么分配
        /**
         * 7个会立即执行，50个进入队列，再开13个线程执行，剩下的30个使用拒绝策略。
         * 如果不想抛弃，可以使用new ThreadPoolExecutor.CallerRunsPolicy()策略方式
         */

//        Executors.newCachedThreadPool() core为0 所有线程都可回收
//        Executors.newFixedThreadPool(10) 固定大小，core=max，，都不可回收
//        Executors.newScheduledThreadPool() 定时任务都线程池
//        Executors.newSingleThreadExecutor() 单线程都线程池，后台从队列中获取任务挨个执行

//=============================================异步线程任务===============================================================
        //异步任务，使用CompletableFuture
        /**
         *  runAsync无返回值
         *  supplyAsync有返回值
         *  whenComplete:用户感知返回值和异常，但不能处理返回值，无返回
         *  exceptionally：发生异常时业务处理，修改返回值等
         *  future.get() 阻塞等待
         *  handle：接收返回，可以处理结果
         *  与whenComplete的区别，whenComplete只能拿到结果，不能处理
         */


//        System.out.println("start======");
        //创建一个异步线程
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("但前线程："+Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("结果:"+i);
//        }, executorService);

        //whenComplete执行成功后获取返回结果，两个参数，一个结果，一个异常
        //exceptionally 异常是会执行
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("但前线程：" + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("结果:" + i);
//
//            return i;
//        }, executorService).whenComplete((result,excption)->{
//            System.out.println("异步任务完成。。。"+ result + "异常："+excption);
//        }).exceptionally(throwable -> {
//            //发生异常时业务处理，修改返回值等
//            return 10;
//        });
//        //future.get() 阻塞等待
//        Integer integer = future.get();
//        System.out.println("end========"+integer);


        //handle方法执行完成后处理结果
        //与whenComplete的区别，whenComplete只能拿到结果，不能处理
        //handle可以处理结果
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("但前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("结果:" + i);
//
//            return i;
//        }).handle((res, excption) -> {
//            if (res != null) {
//                return res * 2;
//            }
//            if (excption != null) {
//                return 0;
//            }
//            return 0;
//        });
//        Integer integer = future.get();
//        System.out.println("end========"+integer);

        //=============================================线程串行化方法===============================================================
        /**
         * thenRun，thenRunAsync不能获取到上一步的执行结果,无返回值
         * thenAccept，thenAcceptAsync能接受上一步返回结果，无返回值
         * thenApply,thenApplyAsync 能接受上一步结果，而且有返回值
         */
//        CompletableFuture.supplyAsync(()->{
//            System.out.println("但前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("结果:" + i);
//
//            return i;
//        }).thenApplyAsync(result->{
//            System.out.println("任务二开始执行");
//
//            return 10;
//        },executorService);

//        System.out.println("end========"+future.get());

//        CompletableFuture.supplyAsync(()->{
//            System.out.println("但前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("结果:" + i);
//
//            return i;
//        }).thenAcceptAsync((result)->{
//            System.out.println("任务二开始执行");
//        },executorService);

//        CompletableFuture.supplyAsync(()->{
//            System.out.println("但前线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("结果:" + i);
//
//            return i;
//        }).thenRunAsync(()->{
//            System.out.println("任务二开始执行");
//        },executorService);

        //=============================================两任务组合，两个任务都完成后做一些事===============================================================
        /**
         * runAfterBoth,runAfterBothAsync:任务一和任务二都结束了才执行，拿不到前两任务都返回，自己也无返回
         * thenAcceptBoth,thenAcceptBothAsync:任务一和任务二都结束了才执行,可以拿到前两任务都返回，但自己也无返回
         * thenCombine,thenCombineAsync:任务一和任务二都结束了才执行,可以拿到前两任务都返回，自己有返回
         */
        //

        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结果:" + i);

            return i;
        }, executorService);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二开始:");
            System.out.println("任务二结果:");
            return "hello";
        }, executorService);

//        future01.runAfterBothAsync(future02,()->{
//            System.out.println("任务三开始:");
//            System.out.println("任务三结果:");
//        },executorService);

//        future01.thenAcceptBothAsync(future02, (f1,f2) -> {
//            System.out.println("任务三开始:"+f1+"-->"+f2);
//        }, executorService);

//        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
//            System.out.println("任务三开始:" + f1 + "-->" + f2);
//
//            return f1 + "---->" + f2 + "---->haha";
//        }, executorService);
//
//        System.out.println(future.get());

        //=============================================两任务中其中一个任务完成后做一些事=======================================
        /**
         * runAfterEither，runAfterEitherAsync:任务一或二有一个结束，任务三开始，不感知前两任务的结果，自已也没有返回值
         * acceptEither,acceptEitherAsync::任务一或二有一个结束，任务三开始，能感知上一个任务的返回，自己没有返回
         * 注意：任务一和任务二两个任务必须是相同的返回类型，不然不好接收
         * applyToEither,applyToEitherAsync:任务一或二有一个结束，任务三开始，能感知上一个任务的返回，自己有返回
         */
//        future01.runAfterEitherAsync(future02,()->{
//            System.out.println("任务一或二有一个结束，任务三开始");
//        },executorService);
//        future01.acceptEitherAsync(future02,(res)->{
//            System.out.println("任务一或二有一个结束，任务三开始");
//        },executorService);

//        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
//            System.out.println("任务一或二有一个结束，任务三开始");
//
//            return res.toString() + "haha";
//        }, executorService);
//
//        System.out.println(future.get());

        //=============================================多任务组合=======================================
        /**
         * allOf:等待多个任务都结束，才获取结果
         * anyOf:多任务中有一个成功
         */
        CompletableFuture<Object> future03 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务三开始:");
            try {
                Thread.sleep(3000);
                System.out.println("任务三结果:");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "任务三";
        }, executorService);

//        CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
//        allOf.get();
        //获取各自任务都内容
//        System.out.println(future01.get(),future02.get(),future03.get());

//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02, future03);
//        anyOf.get();
    }


    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果"+ i);
        }
    }

    public static class Runnable01 implements Runnable {

        @Override
        public void run() {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果"+ i);
        }
    }

    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果"+ i);

            return i;
        }
    }
}
